﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VS2022Offline.Properties;

namespace VS2022Offline
{
    public partial class MainForm: Form
    {
        private string baseFromPath = "https://aka.ms/vs/17/release/";
        private string baseDownPath = Environment.CurrentDirectory;


        public event Action<string> ReadStdOutput;
        public MainForm()
        {
            InitializeComponent();
            Init();
        }
        private void Init()
        {
            this.ReadStdOutput += this.ReadStdOutputAction;
            //this.ReadErrOutput += this.ReadErrOutputAction;

            this.comboBox1.SelectedIndex = 0;
            if (Settings.Default["程序版本"].ToString() != "")
                this.comboBox1.SelectedItem = Settings.Default["程序版本"].ToString();
            if (Settings.Default["缓存目录"].ToString() != "")
                this.txtSaveDirectory.Text = Settings.Default["缓存目录"].ToString();
            string str1 = "";
            string str2 = "";
            if (Settings.Default["选择负载"].ToString() != "")
                str1 = Settings.Default["选择负载"].ToString();
            if (Settings.Default["选择组件"].ToString() != "")
                str2 = Settings.Default["选择组件"].ToString();
            this.treeViewWorkload.Nodes.Clear();
            foreach (VS2022.DicNode workload in VS2022.workloadList)
            {
                TreeNode node1 = new TreeNode();
                node1.Name = workload.Name;
                node1.Text = workload.Text;
                node1.ToolTipText = workload.Tooltip;
                if (str1.IndexOf(workload.Name) > -1)
                {
                    workload.Ischecked = true;
                    node1.Checked = true;
                }
                if (workload.Name == "CoreEditor")
                    node1.Checked = true;
                if (workload.Name == "Others")
                {
                    int num = 0;
                    foreach (VS2022.DicNode component in VS2022.componentList)
                    {
                        TreeNode node2 = new TreeNode();
                        node2.Name = component.Name;
                        node2.Text = component.Text;
                        node2.ToolTipText = component.Tooltip;
                        node1.Nodes.Add(node2);
                        if (str2.IndexOf(component.Name) > -1)
                        {
                            component.Ischecked = true;
                            node2.Checked = true;
                            ++num;
                        }
                    }
                    if (node1.Nodes.Count != num)
                    {
                        node1.Checked = false;
                        workload.Ischecked = false;
                    }
                }
                this.treeViewWorkload.Nodes.Add(node1);
            }
        }

        private void MainForm2_Load(object sender, EventArgs e)
        {

        }


        private string getFileNameByTypeCombox()
        {
            switch (this.comboBox1.SelectedItem.ToString())
            {
                case "Visual Studio Community 2022":
                    return "vs_community";
                case "Visual Studio Professional 2022":
                    return "vs_professional";
                case "Visual Studio Enterprise 2022":
                    return "vs_enterprise";
            }
            return "";
        }

        private void ReadStdOutputAction(string result)
        {
            if (!string.IsNullOrEmpty(result))
                this.txtcmdLogTextArea.AppendText(result + "\r\n");
        }

        private void btnSelectDir_Click(object sender, EventArgs e)
        {
            var folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.ShowNewFolderButton = true;
            if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
                return;
            this.txtSaveDirectory.Text = folderBrowserDialog.SelectedPath;
        }

        private void btnClean_Click(object sender, EventArgs e)
        {
            if (this.comboBox1.SelectedIndex == -1)
            {
                MessageBox.Show(this, "请选择程序版本", "提示");
                return;
            }
            if (this.txtSaveDirectory.Text == "")
            {
                MessageBox.Show(this, "请选择缓存目录", "提示");
                return;
            }

            var cachePath = Path.Combine(this.txtSaveDirectory.Text.Trim(), this.getFileNameByTypeCombox());
            if (!Directory.Exists(cachePath))
            {
                MessageBox.Show(this, "缓存目录不存在，请检查后重试", "提示");
                return;
            }
            var directories1 = new DirectoryInfo(this.txtSaveDirectory.Text).GetDirectories("Archive");
            if (directories1.Length == 0)
            {
                MessageBox.Show(this, "当前缓存目录下文件无需清理", "提示");
            }
            else
            {
                DirectoryInfo[] directories2 = directories1[0].GetDirectories();
                if (directories2.Length == 0)
                {
                    MessageBox.Show(this, "当前缓存目录下文件无需清理", "提示");
                }
                else
                {
                    string str;
                    if (directories2.Length > 1)
                    {
                        MessageBox.Show("当前目录存在多个旧文件记录，请选择指定文件夹下Catalog.json文件，清理旧文件", "提示");
                        OpenFileDialog openFileDialog = new OpenFileDialog();
                        openFileDialog.InitialDirectory = Path.Combine(this.txtSaveDirectory.Text, "Archive");
                        openFileDialog.Multiselect = false;
                        if (openFileDialog.ShowDialog() != DialogResult.OK)
                            return;
                        str = openFileDialog.FileName;
                    }
                    else
                        str = Path.Combine(directories2[0].Name, "Catalog.json");

                    var batPath = Path.Combine(this.txtSaveDirectory.Text.Trim(), this.getFileNameByTypeCombox() + " clean.bat");
                    File.WriteAllText(batPath, $"{this.getFileNameByTypeCombox()}.exe --layout {this.getFileNameByTypeCombox()} --clean " + str);
                    this.RunCmd(batPath);
                }
            }
        }

        private void btnDownlaod_Click(object sender, EventArgs e)
        {
            var url = Path.Combine(this.baseFromPath, this.getFileNameByTypeCombox() + ".exe");
            var offlinePath = Path.Combine(this.txtSaveDirectory.Text.Trim(), this.getFileNameByTypeCombox() + ".exe");
            var downFile = new DownFile(url, offlinePath);
            downFile.StartPosition = FormStartPosition.CenterParent;
            if (downFile.ShowDialog() != DialogResult.OK)
                MessageBox.Show(this, "下载vs程序失败！", "错误");
        }


        bool BuildScript()
        {
            if (this.comboBox1.SelectedIndex == -1)
            {
                MessageBox.Show(this, "请选择程序版本", "提示");
                return false;
            }
            if (string.IsNullOrEmpty(this.txtSaveDirectory.Text.Trim()))
            {
                MessageBox.Show(this, "请选择缓存目录", "提示");
                return false;
            }
            if (!Directory.Exists(this.txtSaveDirectory.Text.Trim()))
            {
                MessageBox.Show(this, "缓存目录不存在，请检查后重试", "提示");
                return false;
            }

            var list1 = VS2022.workloadList.Where(a => a.Ischecked).ToList();
            var list2 = VS2022.componentList.Where(a => a.Ischecked).ToList();
            //             if (list1.Count == 1 && list2.Count == 0 && MessageBox.Show("是否确认只安装核心组件?", "提示", MessageBoxButtons.YesNo) == DialogResult.No)
            //                 return false;
            string str = "";
            foreach (VS2022.DicNode dicNode in list1)
            {
                if (dicNode.Name == "Others")
                {
                    var list3 = VS2022.componentList.Where(a => a.Parentname == "Others").ToList<VS2022.DicNode>();
                    list2 = list2.Concat(list3).ToList();
                }
                else
                    str += $"--add Microsoft.VisualStudio.Workload.{dicNode.Name} ";
            }
            foreach (VS2022.DicNode dicNode in list2)
                str += $"--add {dicNode.Name} ";
            if (str != "")
                str += "--includeRecommended ";
            var catchPath = Path.Combine(this.txtSaveDirectory.Text.Trim(), this.getFileNameByTypeCombox());
            this.txtcmdLogTextArea.Text = $"{this.getFileNameByTypeCombox()} --layout {this.getFileNameByTypeCombox()} {str} --lang Zh-cn";
            var batPath = Path.Combine(this.txtSaveDirectory.Text.Trim(), this.getFileNameByTypeCombox() + " offline.bat");
            File.WriteAllText(batPath, this.txtcmdLogTextArea.Text);

            Settings.Default["程序版本"] = this.comboBox1.SelectedItem.ToString();
            Settings.Default["缓存目录"] = this.txtSaveDirectory.Text.Trim();
            Settings.Default["选择负载"] = string.Join("|", VS2022.workloadList.Where(a => a.Ischecked).Select(d => d.Name));
            Settings.Default["选择组件"] = string.Join("|", VS2022.componentList.Where(a => a.Ischecked).Select(d => d.Name));
            Settings.Default.Save();
            return true;
        }
        private void btnBuild_Click(object sender, EventArgs e)
        {
            BuildScript();
        }

        private void RunCmd(string StartCmd)
        {
            Process process = new Process();
            process.StartInfo.FileName = "cmd.exe";
            process.StartInfo.WorkingDirectory = this.txtSaveDirectory.Text.Trim();
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.OutputDataReceived += (sender, args) => this.Invoke(this.ReadStdOutput, args.Data);
            //process.ErrorDataReceived += (sender, args) => this.Invoke(this.ReadErrOutput, args.Data);
            process.EnableRaisingEvents = true;
            //process.Exited += this.CmdProcess_Exited;
            process.Start();
            process.StandardInput.WriteLine(StartCmd);
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            if (!BuildScript())
                return;

            //this.RunCmd(this.txtcmdLogTextArea.Text);
            this.RunCmd(this.getFileNameByTypeCombox() + " offline.bat");
        }

        private void treeViewWorkload_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Name == "CoreEditor")
            {
                if (e.Node.Checked)
                    return;
                e.Node.Checked = true;
            }
            else
            {
                if (e.Node.Nodes.Count > 0)
                {
                    foreach (TreeNode node in e.Node.Nodes)
                        node.Checked = e.Node.Checked;
                    foreach (VS2022.DicNode dicNode in VS2022.componentList.Where<VS2022.DicNode>((Func<VS2022.DicNode, bool>)(a => a.Parentname == e.Node.Name)).ToList<VS2022.DicNode>())
                        dicNode.Ischecked = e.Node.Checked;
                }
                if (e.Node.Parent != null)
                {
                    int count = e.Node.Parent.Nodes.Count;
                    int num = 0;
                    foreach (TreeNode node in e.Node.Parent.Nodes)
                    {
                        if (node.Checked)
                            ++num;
                    }
                    e.Node.Parent.Checked = count == num;
                }
                VS2022.DicNode dicNode1 = VS2022.workloadList.Find((Predicate<VS2022.DicNode>)(a => a.Name == e.Node.Name));
                if (dicNode1 != null)
                    dicNode1.Ischecked = e.Node.Checked;
                VS2022.DicNode dicNode2 = VS2022.componentList.Find((Predicate<VS2022.DicNode>)(a => a.Name == e.Node.Name));
                if (dicNode2 == null)
                    return;
                dicNode2.Ischecked = e.Node.Checked;
            }
        }
    }
}
